package cn.wch.meshlib.frame.ack;

import androidx.annotation.NonNull;

import java.util.Arrays;
import java.util.function.Predicate;

import cn.wch.blelib.utils.LogUtil;
import cn.wch.meshlib.util.CalculateUtil;

/**
 * 应答命令工具
 */
public class CommandAckUtil {
    /**
     * 应答数据解析
     * @param data 应答的数据包
     * @return
     */
    public static AckFrame parseAck(byte[] data){
        if(data==null || data.length==0){
            return null;
        }
        byte ackType = getAckType(data[0]);
        if(ackType==0){
            LogUtil.d("no match AckType");
            return null;
        }
        return getFrame(ackType,data);
    }

    /**
     * 获取帧
     * @param type 应答类型
     * @param data 应答数据包
     * @return
     */
    private static AckFrame getFrame(@AckType byte type, byte[] data){
        AckFrame frame=new AckFrame(type);
        if(type==AckType.PROVISION){
            //包含 1字节命令码+2字节网络地址+1字节状态码
            if(data.length!=4){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setStatusCode(data[3] & 0xff);
        }else if(type==AckType.PROVISION_INFO){
            //包含1字节命令码+1字节状态码+4字节ivindex+1字节更新标志flag
            if(data.length!=7){
                return null;
            }
            frame.setStatusCode(data[1]);
            frame.setIvIndex(CalculateUtil.littleEndianByteArray2Int(data,2,4));
            frame.setFlag(data[6]);
        } else if(type==AckType.DELETE_NODE){
            //包含 1字节命令码+2字节删除的节点地址+1字节状态码
            if(data.length!=4){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setStatusCode(data[3] & 0xff);
        }else if(type==AckType.DELETE_INFO){
            //包含 1字节命令码+2字节删除的节点地址
            if(data.length!=3){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
        }else if (type==AckType.QUERY_STATE){
            //包含 1字节命令码+2字节网络地址+1字节状态码
            if(data.length!=4){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setStatusCode(data[3] & 0xff);
        }else if(type==AckType.TRANSFER){
            //包含1字节命令码+2字节网络地址+N字节内容
            if(data.length<3){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setData(sliceByteArray(data,3,data.length-3));

        }else if(type==AckType.IMAGE_INFO){
            //包含 1字节命令码+2字节网络地址+4字节image大小+2字节块大小+2字节芯片型号+1字节状态码
            if(data.length!=12){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setImageSize((long)(CalculateUtil.littleEndianByteArray2Int(data,3,4)));
            frame.setBlockSize(CalculateUtil.littleEndianByteArray2Int(data,7,2));
            frame.setChipType(sliceByteArray(data,9,2));
            frame.setStatusCode(data[11]);
        } else if(type==AckType.VERIFY){
            //包含 1字节命令码+2字节网络地址+2字节flash地址+1字节状态码
            if(data.length!=6){
                return null;
            }
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setUpdateAddress(CalculateUtil.littleEndianByteArray2Int(data,3,2));
            frame.setStatusCode(data[5] & 0xff);
        } else if(type==AckType.END){
            if(data.length!=4){
                return null;
            }
            //包含 1字节命令码+2字节网络地址+1字节状态码
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setStatusCode(data[3] & 0xff);
        }else if(type==AckType.UPDATE){
            if(data.length!=6){
                return null;
            }
            //包含1字节命令码+2字节网络地址+2字节flash地址+1字节状态码
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setUpdateAddress(CalculateUtil.littleEndianByteArray2Int(data,3,2));
            frame.setStatusCode(data[5] & 0xff);
        }else if(type==AckType.RESET){
            if(data.length!=2){
                return null;
            }
            //包含1字节命令码+1字节状态码
            frame.setStatusCode(data[1] & 0xff);
        }else if(type==AckType.SUBSCRIBE){
            if(data.length!=4){
                return null;
            }
            //包含1字节命令码+1字节状态码
            frame.setNetAddress(CalculateUtil.littleEndianByteArray2Int(data,1,2));
            frame.setStatusCode(data[3] & 0xff);
        }
        return frame;
    }

    /**
     * 获取应答类型
     * @param type
     * @return
     */
    private static @AckType byte getAckType(byte type){
        if(type==AckType.PROVISION_INFO) {
            return AckType.PROVISION_INFO;
        }else if(type==AckType.PROVISION){
            return AckType.PROVISION;
        }else if(type==AckType.DELETE_NODE){
            return AckType.DELETE_NODE;
        }else if(type==AckType.DELETE_INFO){
            return AckType.DELETE_INFO;
        }else if(type==AckType.QUERY_STATE){
            return AckType.QUERY_STATE;
        }else if(type==AckType.TRANSFER){
            return AckType.TRANSFER;
        }else if(type==AckType.IMAGE_INFO){
            return AckType.IMAGE_INFO;
        }else if(type==AckType.VERIFY){
            return AckType.VERIFY;
        }else if(type==AckType.END){
            return AckType.END;
        }else if(type==AckType.UPDATE){
            return AckType.UPDATE;
        }else if(type==AckType.SUBSCRIBE){
            return AckType.SUBSCRIBE;
        }else if(type==AckType.RESET){
            return AckType.RESET;
        }else {
            return 0;
        }
    }

    /**
     * 裁剪二进制数据
     * @param data 需要裁剪的源数据
     * @param start 裁剪的开始位置
     * @param len 裁剪的数据长度
     * @return 成功，裁剪后的数据。失败，null
     */
    private static byte[] sliceByteArray(@NonNull byte[] data, int start,int len){
        if(data.length==0 || (start+len>data.length)){
            return null;
        }
        byte[] temp=new byte[len];
        System.arraycopy(data,start,temp,0,len);
        return temp;
    }
}
